//-----------------------------------------------------------------------------
// Author: JCBDigger
// URL: http://Games.DiscoverThat.co.uk
// Based on samples from the Internet including and thanks to:
//  Dean Lunz: http://www.createdbyx.com/page/Winform-controls-in-XNA.aspx
//  Roy Triesscheijn: http://roy-t.nl/index.php/2008/10/09/xna-30-and-winforms-the-easy-way/
//  Microsoft: http://create.msdn.com/en-US/education/catalog/sample/winforms_series_1
//-----------------------------------------------------------------------------
// Reference:
//  http://msdn.microsoft.com/en-us/library/system.windows.forms.menustrip.aspx
// Creating the WinForm in the game may not fully work
//  http://msdn.microsoft.com/en-us/library/ms229591(v=VS.100).aspx
// The workround is to use a dialogue to launch the form
//  http://msdn.microsoft.com/en-us/library/ms229611.aspx
//  This is modal and can suspend the underlying app.
//  It is OK for popup forms but not good for menus.  
//  Background transparency is not supported so a fake menu using a dialogue also did not work!
// To get the result see:
// http://msdn.microsoft.com/en-us/library/system.windows.forms.form.dialogresult.aspx
//  Remember to dispose the form after use
//-----------------------------------------------------------------------------
// Limitations:
//  The arrows sometimes work in reverse for the top menu once any menu is dropped 
//      down!  This appears to depend on what items are on the dropped down menus.
//      Adding the Sub menu to the file menu made the arrows work the correct
//      way round!
//  All top menu items must be drop down menus otherwise the arrows change from 
//      forward to reverse mid way along while using the menus!
//  The top menu must be disabled when not in use otherwise it continues to 
//      react to keyboard movement in the game!
//-----------------------------------------------------------------------------

#region MIT License
/*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
// To avoid ambiguous structure names
using Point = System.Drawing.Point;
using ButtonState = Microsoft.Xna.Framework.Input.ButtonState;
using Keys = Microsoft.Xna.Framework.Input.Keys;

namespace Engine
{
    /// <summary>
    /// This is the main class for your game
    /// </summary>
    public class GameWithMenus : Microsoft.Xna.Framework.Game
    {
        private GraphicsDeviceManager graphics;
        private KeyboardState currentKeyState;
        private KeyboardState previousKeyState;
        private SpriteBatch spriteBatch;
        private Texture2D sampleImage;

        private MenuStrip topMenu = new MenuStrip();
        // So we can reference some menu items specifically
        private ToolStripMenuItem fileMenu;
        private ToolStripMenuItem toolsMenu;
        private ToolStripMenuItem windowMenu;

        private const int buttonSpacing = 12;

        public GameWithMenus()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // Show the mouse when required
            IsMouseVisible = false;
            // The back buffer must be the same size as the viewport
            Window.AllowUserResizing = false;

            // Winform
            SetupControls();
        }


        //////////////////////////////////////////////////////////////////////
        // == Form stuff ==
        //
        private void SetupControls()
        {
            Form winForm = Control.FromHandle(Window.Handle) as Form;
            
            PopulateMenu(winForm);
            HideTopMenu();
        }

        /// <summary>
        /// Call this to ensure that the menu is enabled or disabled and that options
        /// are set consistently.
        /// </summary>
        private void UpdateMenuOptions()
        {
            // Make sure the menu only accepts input when it is supposed to
            topMenu.Enabled = topMenu.Visible;
            // Show the mouse when required
            IsMouseVisible = topMenu.Visible;
            // Make sure the menu has focus if it is visible
            if (topMenu.Visible)
            {
                topMenu.Focus();
                fileMenu.Select();
            }
            // Add additional settings here
            // For example: 
            //      enabled any Checked (ticked) items.
        }

        private void ToggleMenuDisplay()
        {
            topMenu.Visible = !topMenu.Visible;
            UpdateMenuOptions();
        }

        /// <summary>
        /// Call this to close and disable the top menu
        /// </summary>
        private void HideTopMenu()
        {
            topMenu.Visible = false;
            UpdateMenuOptions();
        }

        private void PopulateMenu(Form winForm)
        {
            // Create a MenuStrip control with a new window.
            fileMenu = new ToolStripMenuItem("&File");

            // Add a sub menu
            ToolStripMenuItem addMenu = new ToolStripMenuItem("&Add or Edit...");
            ToolStripMenuItem addEdit1Menu = new ToolStripMenuItem("&Something", null, new EventHandler(addEdit1Menu_Click));
            ToolStripMenuItem addEdit2Menu = new ToolStripMenuItem("&Else", null, new EventHandler(addEdit2Menu_Click));
            addMenu.DropDownItems.Add(addEdit1Menu);
            addMenu.DropDownItems.Add(addEdit2Menu);
            ((ToolStripDropDownMenu)(addMenu.DropDown)).ShowImageMargin = false;
            ((ToolStripDropDownMenu)(addMenu.DropDown)).ShowCheckMargin = true;
            fileMenu.DropDownItems.Add(addMenu);

            // Continue to add to the file menu
            ToolStripSeparator fileSeparator1 = new ToolStripSeparator();
            ToolStripMenuItem fileExitMenu = new ToolStripMenuItem("E&xit", null, new EventHandler(fileExitMenu_Click));
            fileMenu.DropDownItems.Add(fileSeparator1);
            fileMenu.DropDownItems.Add(fileExitMenu);
            ((ToolStripDropDownMenu)(fileMenu.DropDown)).ShowImageMargin = false;
            ((ToolStripDropDownMenu)(fileMenu.DropDown)).ShowCheckMargin = true;

            // More top menu items
            toolsMenu = new ToolStripMenuItem("&Tools");
            ToolStripMenuItem toolsShowPopup1Menu = new ToolStripMenuItem("&Preset Lists Form", null, new EventHandler(toolsShowPopup1Menu_Click));
            ToolStripMenuItem toolsShowPopup2Menu = new ToolStripMenuItem("&Up Down Lists Form", null, new EventHandler(toolsShowPopup2Menu_Click));
            ToolStripMenuItem toolsShowPopup3Menu = new ToolStripMenuItem("&Designer Form", null, new EventHandler(toolsShowPopup3Menu_Click));
            toolsMenu.DropDownItems.Add(toolsShowPopup1Menu);
            toolsMenu.DropDownItems.Add(toolsShowPopup2Menu);
            toolsMenu.DropDownItems.Add(toolsShowPopup3Menu);
            ((ToolStripDropDownMenu)(toolsMenu.DropDown)).ShowImageMargin = false;
            ((ToolStripDropDownMenu)(toolsMenu.DropDown)).ShowCheckMargin = true;

            windowMenu = new ToolStripMenuItem("&Window");
            ToolStripMenuItem windowCloseMenu = new ToolStripMenuItem("&Close", null, new EventHandler(windowCloseMenu_Click));
            windowMenu.DropDownItems.Add(windowCloseMenu);
            ((ToolStripDropDownMenu)(windowMenu.DropDown)).ShowImageMargin = false;
            ((ToolStripDropDownMenu)(windowMenu.DropDown)).ShowCheckMargin = true;

            // Add the menu items to the menu
            topMenu.Items.Add(fileMenu);
            topMenu.Items.Add(toolsMenu);
            topMenu.Items.Add(windowMenu);
            
            // Dock the MenuStrip to the top of the form.
            topMenu.Dock = DockStyle.Top;

            winForm.Controls.Add(topMenu);
        }

        // == Event handlers for the menu and button actions

        private void fileExitMenu_Click(object sender, EventArgs e)
        {
            // Exit the game
            Exit();
        }

        private void addEdit1Menu_Click(object sender, EventArgs e)
        {
            topMenu.Visible = false;
            IsMouseVisible = true;
            MessageBox.Show("Add Edit 1 selected.");
            HideTopMenu();
        }

        private void addEdit2Menu_Click(object sender, EventArgs e)
        {
            topMenu.Visible = false;
            IsMouseVisible = true;
            MessageBox.Show("Add Edit 2 selected.");
            HideTopMenu();
        }

        private void toolsShowPopup1Menu_Click(object sender, EventArgs e)
        {
            FormWithTypicalControls();
        }

        private void toolsShowPopup2Menu_Click(object sender, EventArgs e)
        {
            FormWithUpDownList();
        }

        private void toolsShowPopup3Menu_Click(object sender, EventArgs e)
        {
            FormDesigned();
        }

        private void windowCloseMenu_Click(object sender, EventArgs e)
        {
            HideTopMenu();
        }

        // Create a popup on the fly and dispose afterwards
        private void FormWithTypicalControls()
        {
            topMenu.Visible = false;
            // Show the mouse when required
            IsMouseVisible = true;

            // Size of the overall control including the borders
            int width = 250;    // 250
            int height = 420;

            Form popupForm = new Form();
            popupForm.Text = "Popup Form";
            popupForm.StartPosition = FormStartPosition.CenterParent;
            popupForm.MaximizeBox = false;
            popupForm.MinimizeBox = false;
            popupForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            popupForm.Size = new System.Drawing.Size(width, height);
            popupForm.MinimumSize = new System.Drawing.Size(width, height);
            popupForm.Size = popupForm.MinimumSize;

            // Get the usable size
            width = popupForm.ClientSize.Width;
            height = popupForm.ClientSize.Height;

            // Cancel button
            Button btnCancel = new Button();
            btnCancel.Text = "Cancel";
            btnCancel.TabStop = true;
            btnCancel.TabIndex = 50;
            btnCancel.Location = new Point(width - buttonSpacing - btnCancel.Width, height - buttonSpacing - btnCancel.Height);
            // What to do when clicked
            btnCancel.DialogResult = DialogResult.Cancel;
            // Add the button to the panel
            popupForm.Controls.Add(btnCancel);

            // OK button
            Button btnOK = new Button();
            btnOK.Text = "OK";
            btnOK.TabStop = true;
            btnOK.TabIndex = btnCancel.TabIndex - 1;
            btnOK.Location = new Point(btnCancel.Location.X - buttonSpacing - btnOK.Width, btnCancel.Location.Y);
            // What to do when clicked
            btnOK.DialogResult = DialogResult.OK;
            // Add the button to the panel
            popupForm.Controls.Add(btnOK);

            // Text label
            Label textLabel = new Label();
            textLabel.Text = "This box pops up\nwhen chosen.";
            textLabel.Location = new Point(buttonSpacing, buttonSpacing);
            textLabel.AutoSize = true;
            popupForm.Controls.Add(textLabel);

            // Simple list
            string[] itemList = new string[4] { "A", "B", "C", "D" };
            ListBox listPanel = new ListBox();
            listPanel.TabIndex = 0;
            listPanel.Location = new Point(buttonSpacing, textLabel.Top + textLabel.Height + (buttonSpacing * 2));
            //Use the internal list
            for (int i = 0; i < itemList.Length; i++)
            {
                listPanel.Items.Add(itemList[i]);
            }
            // With an internal list it is easy to display the selected item
            listPanel.SelectedIndex = 2;
            popupForm.Controls.Add(listPanel);

            // Drop down list
            string[] exterList = new string[4] { "E", "F", "G", "H" };
            ComboBox exterBox = new ComboBox();
            exterBox.TabIndex = listPanel.TabIndex + 1;
            exterBox.Location = new Point(buttonSpacing, listPanel.Top + listPanel.Height + (buttonSpacing * 2));
            // Use an external datasource
            exterBox.DataSource = exterList;
            popupForm.Controls.Add(exterBox);

            // Drop down list
            string[] interList = new string[4] { "E", "F", "G", "H" };
            ComboBox interBox = new ComboBox();
            interBox.TabIndex = listPanel.TabIndex + 1;
            interBox.Location = new Point(buttonSpacing, exterBox.Top + exterBox.Height + buttonSpacing);
            // Use the internal list
            interBox.Items.AddRange(interList);
            // With an internal list it is easy to display the selected item
            interBox.SelectedIndex = 1;
            popupForm.Controls.Add(interBox);

            // Text label
            Label nameLabel = new Label();
            nameLabel.Text = "Name:";
            nameLabel.Location = new Point(buttonSpacing, interBox.Location.Y + buttonSpacing + interBox.Height);
            nameLabel.AutoSize = true;
            popupForm.Controls.Add(nameLabel);

            // Text Entry
            TextBox nameEntry = new TextBox();
            nameEntry.TabIndex = exterBox.TabIndex + 1;
            nameEntry.Text = "Something";
            nameEntry.Location = new Point(nameLabel.Location.X + nameLabel.Width + buttonSpacing, nameLabel.Location.Y);
            popupForm.Controls.Add(nameEntry);

            // Text label
            Label radiusLabel = new Label();
            radiusLabel.Text = "Circle Radius:";
            radiusLabel.Location = new Point(buttonSpacing, nameEntry.Location.Y + buttonSpacing + nameEntry.Height);
            radiusLabel.AutoSize = true;
            popupForm.Controls.Add(radiusLabel);

            // Numeric Entry
            // Uses decimal.  Either cast to decimal or use the literal indicator M
            NumericUpDown radiusEntry = new NumericUpDown();
            radiusEntry.TabIndex = nameEntry.TabIndex + 1;
            radiusEntry.DecimalPlaces = 2;
            radiusEntry.Maximum = 10m;
            radiusEntry.Minimum = 0.2m;
            radiusEntry.Increment = 0.1m;
            radiusEntry.Value = (decimal)4.5;
            radiusEntry.Location = new Point(radiusLabel.Location.X + radiusLabel.Width + buttonSpacing, radiusLabel.Location.Y);
            popupForm.Controls.Add(radiusEntry);

            // Display the model form
            popupForm.ShowDialog();

            if (popupForm.DialogResult == DialogResult.OK)
            {
                // Display a message box indicating that the OK button was clicked.
                MessageBox.Show("The OK button on the form was clicked.\n" +
                    "The Radius value is: " + radiusEntry.Value);
                // Save any poperties here before the form is disposed of
            }

            // Must dispose of the form so that ShowDialog() can be reused otherwise the form is only hidden
            popupForm.Dispose();
            // Close the other menus
            HideTopMenu();
        }

        // Create a popup on the fly and dispose afterwards
        private void FormWithUpDownList()
        {
            topMenu.Visible = false;
            // Show the mouse when required
            IsMouseVisible = true;

            // Size of the overall control including the borders
            int width = 450;
            int height = 420;
            int column = 110;

            Form popupForm = new Form();
            popupForm.Text = "Sort ListBox Control Sample";
            popupForm.StartPosition = FormStartPosition.CenterParent;
            popupForm.MaximizeBox = false;
            popupForm.MinimizeBox = false;
            popupForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            popupForm.Size = new System.Drawing.Size(width, height);
            popupForm.MinimumSize = new System.Drawing.Size(width, height);
            popupForm.Size = popupForm.MinimumSize;

            // Get the usable size
            width = popupForm.ClientSize.Width;
            height = popupForm.ClientSize.Height;

            // Cancel button
            Button btnCancel = new Button();
            btnCancel.Text = "Cancel";
            btnCancel.TabStop = true;
            btnCancel.TabIndex = 50;
            btnCancel.Location = new Point(width - buttonSpacing - btnCancel.Width, height - buttonSpacing - btnCancel.Height);
            // What to do when clicked
            btnCancel.DialogResult = DialogResult.Cancel;
            // Add the button to the panel
            popupForm.Controls.Add(btnCancel);

            // OK button
            Button btnOK = new Button();
            btnOK.Text = "OK";
            btnOK.TabStop = true;
            btnOK.TabIndex = btnCancel.TabIndex - 1;
            btnOK.Location = new Point(btnCancel.Location.X - buttonSpacing - btnOK.Width, btnCancel.Location.Y);
            // What to do when clicked
            btnOK.DialogResult = DialogResult.OK;
            // Add the button to the panel
            popupForm.Controls.Add(btnOK);

            // Text label
            Label textLabel = new Label();
            textLabel.Text = "Demonstrate the up down list box control.";
            textLabel.Location = new Point(buttonSpacing, buttonSpacing);
            textLabel.AutoSize = true;
            popupForm.Controls.Add(textLabel);

            // Text label
            Label listLabel = new Label();
            listLabel.Text = "List:";
            listLabel.Location = new Point(
                buttonSpacing,
                textLabel.Top + (buttonSpacing * 2) + textLabel.Height);
            listLabel.AutoSize = true;
            popupForm.Controls.Add(listLabel);

            // Up down list
            string[] itemList = new string[6] { "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot" };
            List<string> theItems = new List<string>();
            theItems.AddRange(itemList);
            UpDownListControl listPanel = new UpDownListControl();
            listPanel.TabIndex = 0;
            listPanel.Location = new Point(
                column, 
                listLabel.Top);
            listPanel.AddRange(theItems);
            listPanel.SelectedIndex = 2;
            listPanel.ButtonAdd.Click += new EventHandler(ButtonAdd_Click);
            popupForm.Controls.Add(listPanel);


            // Display the model form
            popupForm.ShowDialog();

            if (popupForm.DialogResult == DialogResult.OK)
            {
                // Display a message box indicating that the OK button was clicked.
                MessageBox.Show("The OK button on the form was clicked.");
                // Save any poperties here before the form is disposed of
            }

            // Must dispose of the form so that ShowDialog() can be reused otherwise the form is only hidden
            popupForm.Dispose();
            // Close the other menus
            HideTopMenu();
        }

        private void ButtonAdd_Click(object sender, EventArgs e)
        {
            Button btn = (System.Windows.Forms.Button)sender;
            UpDownListControl list = (UpDownListControl)btn.Parent;
            list.AddAndSelect("Test at: " + DateTime.Now.ToShortTimeString());
        }

        // Create a popup on the fly and dispose afterwards
        private void FormDesigned()
        {
            topMenu.Visible = false;
            // Show the mouse when required
            IsMouseVisible = true;

            PopupFormExample popupForm = new PopupFormExample();
            popupForm.Text = "Designer Form Example";

            // Display the model form
            popupForm.ShowDialog();

            if (popupForm.DialogResult == DialogResult.OK)
            {
                // Display a message box indicating that the OK button was clicked.
                MessageBox.Show("The OK button on the form was clicked.");
                // Save any poperties here before the form is disposed of
            }

            // Must dispose of the form so that ShowDialog() can be reused otherwise the form is only hidden
            popupForm.Dispose();
            // Close the other menus
            HideTopMenu();
        }
        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        // == Game stuff ==
        //
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
             // Sample image that will fill the viewport
            sampleImage = Content.Load<Texture2D>("Stars1");

            // Initialise the keyboard
            currentKeyState = Keyboard.GetState();
            previousKeyState = Keyboard.GetState();

        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        protected override void Update(GameTime gameTime)
        {
            // Must be before any keys are processed
            currentKeyState = Keyboard.GetState();

            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                currentKeyState.IsKeyDown(Keys.Escape))
            {
                Exit();
            }

            // Display the menu
            if (currentKeyState.IsKeyDown(Keys.LeftAlt) &&
                previousKeyState.IsKeyUp(Keys.LeftAlt))
            {
                ToggleMenuDisplay();
            }

            // Simulate menu shortcut keys
            if (topMenu.Visible)
            {
                if (currentKeyState.IsKeyDown(Keys.F) &&
                    previousKeyState.IsKeyUp(Keys.F))
                {
                    fileMenu.Select();
                    fileMenu.ShowDropDown();
                    fileMenu.DropDownItems[0].Select();
                }
                if (currentKeyState.IsKeyDown(Keys.T) &&
                    previousKeyState.IsKeyUp(Keys.T))
                {
                    toolsMenu.Select();
                    toolsMenu.ShowDropDown();
                    toolsMenu.DropDownItems[0].Select();
                }
                if (currentKeyState.IsKeyDown(Keys.W) &&
                    previousKeyState.IsKeyUp(Keys.W))
                {
                    windowMenu.Select();
                    windowMenu.ShowDropDown();
                    windowMenu.DropDownItems[0].Select();
                }

            }

            // Must be after all keyboard entry has been processed for this update
            previousKeyState = currentKeyState;

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            // Draw the background image to fill the window
            spriteBatch.Begin();
            Rectangle destination = new Rectangle(
                GraphicsDevice.Viewport.X, GraphicsDevice.Viewport.Y,
                GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            Rectangle source = new Rectangle(0, 0, sampleImage.Width, sampleImage.Height);
            spriteBatch.Draw(sampleImage, destination, source, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
        //
        //////////////////////////////////////////////////////////////////////


    }
}
